using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Security.Principal;
using InfiniTec.Exchange.Notifications.Microsoft.Exchange.WebServices;

namespace InfiniTec.Exchange.Notifications
{
	/// <summary>
	/// Contains information about impersonation settings used for the Exchange calls. See http://msdn.microsoft.com/en-us/library/bb204095.aspx
	/// for more informations about the Exchange 2007 impersonation.
	/// </summary>
	[Serializable]
	public sealed class ImpersonationSettings: ISerializable
	{
		/// <summary>
		/// Gets or sets the primary SMTP address of the user to impersonate.
		/// </summary>
		/// <value>The primary SMTP address.</value>
		public string PrimarySmtpAddress { get; set;}
		/// <summary>
		/// Gets or sets the user principal name (UPN) of the user to impersonate.
		/// </summary>
		/// <value>The name of the principal.</value>
		public string PrincipalName { get; set; }
		/// <summary>
		/// Gets or sets the <see cref="SecurityIdentifier"/> of the user to impersonate.
		/// </summary>
		/// <value>The security identifier.</value>
		public SecurityIdentifier SecurityIdentifier { get; set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="ImpersonationSettings"/> class.
		/// </summary>
		public ImpersonationSettings()
		{
		}

		/// <summary>
		/// Converts the current instance to an ExchangeImpersonationType instance usable for webservice calls.
		/// </summary>
		/// <returns></returns>
		internal ExchangeImpersonationType ToExchangeImpersonationType()
		{
			if (!string.IsNullOrEmpty(PrimarySmtpAddress))
			{
				return new ExchangeImpersonationType
				       	{ConnectingSID = new ConnectingSIDType {PrimarySmtpAddress = PrimarySmtpAddress}};
			}
			if (!string.IsNullOrEmpty(PrincipalName))
			{
				return new ExchangeImpersonationType { ConnectingSID = new ConnectingSIDType { PrincipalName = PrincipalName} };
			}
			if (SecurityIdentifier != null)
			{
				return new ExchangeImpersonationType { ConnectingSID = new ConnectingSIDType { SID = SecurityIdentifier.Value} };
			}

			return null;
		}

		/// <summary>
		/// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object.
		/// </summary>
		/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data.</param>
		/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization.</param>
		/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception>
		[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("PrimarySmtpAddress", PrimarySmtpAddress);
			info.AddValue("PrincipalName", PrincipalName);
			if (SecurityIdentifier != null)
			{
				info.AddValue("SecurityIdentifier", SecurityIdentifier.Value);
			}
			else
			{
				info.AddValue("SecurityIdentifier", null);
			}
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ImpersonationSettings"/> class.
		/// </summary>
		/// <param name="info">The info.</param>
		/// <param name="context">The context.</param>
		private ImpersonationSettings(SerializationInfo info, StreamingContext context)
		{
			PrimarySmtpAddress = info.GetString("PrimarySmtpAddress");
			PrincipalName = info.GetString("PrincipalName");
			
			var sddlForm = info.GetString("SecurityIdentifier");
			if (!string.IsNullOrEmpty(sddlForm))
			{
				SecurityIdentifier = new SecurityIdentifier(sddlForm);
			}
		}
	}
}